package com.lcf.framework.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel;
import cn.idev.excel.write.metadata.WriteSheet;
import cn.idev.excel.write.metadata.style.WriteCellStyle;
import cn.idev.excel.write.metadata.style.WriteFont;
import cn.idev.excel.write.style.HorizontalCellStyleStrategy;
import com.lcf.framework.exception.SysException;
import com.lcf.framework.query.PageQuery;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

import static com.lcf.framework.constant.SysConstant.DEFAULT_EXPORT_BATCH_SIZE;


/**
 * excel写
 *
 * @author lcf
 */
public class ExcelWriteUtils {
    /**
     * 分批多次写入，可实现大数据量的分页写入。
     *
     * @param fileName 文件名
     * @param query    分页查询条件
     * @param clazz    导出实体类
     * @param function 查询方法
     */
    public static <E, T, Q extends PageQuery<E>> void write(String fileName, Q query, Class<T> clazz, Function<Q, List<T>> function) {
        write(fileName, "数据", query, clazz, function);
    }

    /**
     * 一次性导出
     */
    public static <T> void write(String fileName, Class<T> clazz, List<T> data) {
        write(fileName, "数据", clazz, data);
    }

    /**
     * 分批多次写入，可实现大数据量的分页写入。
     *
     * @param fileName  文件名
     * @param sheetName sheet名
     * @param query     分页查询条件
     * @param clazz     导出实体类
     * @param function  查询方法
     */
    public static <E, T, Q extends PageQuery<E>> void write(String fileName, String sheetName,
                                                            Q query, Class<T> clazz, Function<Q, List<T>> function) {
        HttpServletResponse response = setResponse(fileName);
        HorizontalCellStyleStrategy strategy = new HorizontalCellStyleStrategy(headStyle(), contentStyle());
        try (ExcelWriter excelWriter = FastExcel.write(response.getOutputStream(), clazz).registerWriteHandler(strategy).build()) {
            WriteSheet writeSheet = FastExcel.writerSheet(sheetName).build();

            query.setPageNum(1);
            query.setPageSize(DEFAULT_EXPORT_BATCH_SIZE);

            List<T> data = function.apply(query);

            //翻译
            EntityTranslateUtils bean = SpringUtil.getBean(EntityTranslateUtils.class);
            bean.translate(data);

            while (CollectionUtil.isNotEmpty(data)) {
                excelWriter.write(data, writeSheet);

                //查询下一页
                query.setPageNum(query.getPageNum() + 1);
                data = function.apply(query);
            }
        } catch (IOException e) {
            throw new SysException(e);
        }
    }

    /**
     * 一次性导出
     */
    public static <T> void write(String fileName, String sheetName, Class<T> clazz, List<T> data) {
        HttpServletResponse response = setResponse(fileName);

        //翻译
        EntityTranslateUtils bean = SpringUtil.getBean(EntityTranslateUtils.class);
        bean.translate(data);

        try {
            FastExcel.write(response.getOutputStream(), clazz)
                    .sheet(sheetName)
                    .registerWriteHandler(new HorizontalCellStyleStrategy(headStyle(), contentStyle()))
                    .doWrite(data);
        } catch (IOException e) {
            throw new SysException(e);
        }
    }

    private static HttpServletResponse setResponse(String fileName) {
        HttpServletResponse response = ServletUtils.getResponse();
        Objects.requireNonNull(response).setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");

        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        return response;
    }

    /**
     * 定义表头样式
     */
    private static WriteCellStyle headStyle() {

        WriteCellStyle headStyle = new WriteCellStyle();
        // 背景
        headStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        //字体
        WriteFont headFont = new WriteFont();
        headFont.setFontName("微软雅黑");
        headFont.setFontHeightInPoints((short) 12);
        headFont.setBold(false);
        headStyle.setWriteFont(headFont);
        // 去除填充色
        headStyle.setFillPatternType(FillPatternType.NO_FILL);
        //边框颜色
        headStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());

        return headStyle;
    }

    /**
     * 定义内容样式
     */
    private static WriteCellStyle contentStyle() {
        // 定义内容样式
        WriteCellStyle contentStyle = new WriteCellStyle();
        contentStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        contentStyle.setFillPatternType(FillPatternType.NO_FILL);
        WriteFont contentFont = new WriteFont();
        contentFont.setFontName("微软雅黑");
        contentFont.setFontHeightInPoints((short) 10);
        contentStyle.setWriteFont(contentFont);

        return contentStyle;
    }
}
